package common.ui
{
	
	import flash.display.BlendMode;
	import flash.display.DisplayObject;
	import flash.display.InteractiveObject;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.filters.DropShadowFilter;
	import flash.filters.GlowFilter;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;
	
	import kernel.application.ApplicationDisplay;
	import kernel.core.ObjectFactory;
	
	
	public class Xtip extends Sprite
	{
		/**
		 * 新 ToolTip 控件的最大宽度（以像素为单位）。大于此宽度文本将自动换行。
		 */ 
		public static var maxWidth:Number=500;
		/**
		 * 是否让提示实时跟随鼠标移动
		 */ 
		public static var isFollowMouse:Boolean = true;
		/**
		 * 提示文本的全局样式（影响所有ToolTip实例）
		 */ 
		public static var textFormat:TextFormat;
		/**
		 * 提示文本的顶部边距（全局设置，影响所有ToolTip实例）
		 */ 
		public static var paddingTop:Number = 3;
		/**
		 * 提示文本的左边距（全局样设置，影响所有ToolTip实例）
		 */ 
		public static var paddingLeft:Number = 6;
		/**
		 * 提示文本的淡入的速度，如果需要关闭淡入，将此值设置为1，请勿使用0或者负数（全局设置，影响所有ToolTip实例）
		 */ 
		public static var alphaIn:Number = 0.1;
		/**
		 * 提示文本的淡出的速度，如果需要关闭淡出，将此值设置为1，请勿使用0或者负数（全局设置，影响所有ToolTip实例）
		 */ 
		public static var alphaOut:Number = 0.05*4;
		/**
		 * 提示文本背景的滤镜，默认是一个阴影滤镜（全局设置，影响所有ToolTip实例）
		 */ 
		public static var backgroundFilter:Array = [new DropShadowFilter(4,45,0,1,4,4,0.3,1)];
		public static var txtFilter:Array = [new GlowFilter(0x0,1,2,2,3,1)];
		
		private static var tips:Array = new Array();
		private static var timer:Timer = new Timer(700);
		private static var isOn:Boolean = false;
		private static var target:InteractiveObject;
		private static var tip:Object;
		private static var ins:Xtip;
		private static var timeOutID:uint;
		private static var linkTips:Array = [];
		private static var nowLinkTip:Sprite;
		private static var nowDis:DisplayObject;
		
		private static var defaultToolTipStyle:Object;
		
		public static var stage:Stage;
		
		private var txt:TextField;
		private var _tipValue:Object;
		protected var _compoWidth:Number = 10;
		protected var _compoHeight:Number = 10;
		
		private var bg:Sprite;
		
		/**
		 * 创建一个新的 ToolTip 组件实例
		 */ 
		public function Xtip()
		{
			super();
			
			if(textFormat == null){
				textFormat = new TextFormat();
				textFormat.font = "_sans";
				textFormat.size = 12;
			}
			
			
		}
		/**
		 * 获得组件的宽度，此宽度并不一定等同于DisplayObject的width。是setSize的宽度
		 * 
		 * @see #setSize()
		 * @see flash.display.DisplayObject
		 */ 
		public function get compoWidth():Number {
			return _compoWidth;
		}
		public static function get nowTooltipView():Xtip{
			return ins;
		}
		/**
		 * 获得组件的高度，此宽度并不一定等同于DisplayObject的height。是setSize的高度度
		 * 
		 * @see #setSize()
		 * @see flash.display.DisplayObject
		 */ 
		public function get compoHeight():Number {
			return _compoHeight;
		}
		public function alphaInInit():void{
			this.alpha = 0;
			this.removeEventListener(Event.ENTER_FRAME,alphaOutFrame);
			this.addEventListener(Event.ENTER_FRAME,alphaInFrame);
		}
		public function alphaOutInit():void{
			this.removeEventListener(Event.ENTER_FRAME,alphaInFrame);
			this.addEventListener(Event.ENTER_FRAME,alphaOutFrame);
		}
		
		/**
		 * 设置提示，接受简单String，HTML String，图像URL Request，BitmapData,库链接，DisplayObject
		 */
		public function set tip(value:Object):void{
			_tipValue =value;
			
			if(txt == null){
				txt = new TextField();
				this.addChild(txt);
				txt.multiline = true;
				txt.wordWrap = true;
			}
			txt.textColor = 0xFFFFFF;
			txt.htmlText = String(value);
			txt.setTextFormat(textFormat);
			txt.x = paddingLeft;
			txt.y = paddingTop;
			txt.width =maxWidth;
			txt.width = txt.textWidth+5;
			txt.height = txt.textHeight+5;
			//txt.blendMode = BlendMode.LAYER;
			txt.filters = txtFilter;
			
			_compoWidth = txt.width+paddingLeft*2-3;
			_compoHeight = txt.height+paddingTop*2-1;
			
			//setSize(_compoWidth,_compoHeight);
			skinDisplayObject.filters = backgroundFilter;
			if(this.stage == null) return;
			if(this.x+_compoWidth+3>this.stage.stageWidth){
				this.x = this.stage.stageWidth - _compoWidth-3;
			}
			if(this.y + _compoHeight+3>this.stage.stageHeight){
				this.y = this.stage.mouseY-_compoHeight-5;
			}
			if(bg == null){
				bg = ObjectFactory.getNewSprite("toolTipBackground");
				this.addChildAt(bg,0);
				this.mouseChildren = false;
				this.mouseEnabled = false;
			}
			bg.width = _compoWidth;
			bg.height = _compoHeight+1;
		}
		public function get tip():Object{
			return _tipValue;
		}
		/**
		 * 获得文本框实例的引用
		 */ 
		public function get textField():TextField{
			return txt;
		}
		/**
		 * 获得背景实例的引用
		 */
		public function get skinDisplayObject():DisplayObject{
			return new Shape();
		}
		private function alphaInFrame(event:Event):void{
			this.alpha += alphaIn;
			if(this.alpha>=1){
				this.alpha = 1;
				this.removeEventListener(Event.ENTER_FRAME,alphaInFrame);
			}
		}
		private function alphaOutFrame(event:Event):void{
			this.alpha -= alphaOut;
			if(this.alpha<=0){
				this.alpha = 0;
				this.removeEventListener(Event.ENTER_FRAME,alphaOutFrame);
				if(this.parent != null){
					this.parent.removeChild(this);
				}
			}
		}
		/**
		 * 对一个可交互的显示对象启用提示，此提示将获得和组件一样的行为
		 */ 
		public static function registerTip(display:DisplayObject,tip:Object):void{
			var interDisplay:InteractiveObject = display as InteractiveObject;
			if(interDisplay == null) return;
		
			if(target == interDisplay){
				if(ins != null)
				{
					ins.tip = tip;
				}
			}else{	
				clearTip(interDisplay);
				tips.push([interDisplay,tip]);
				interDisplay.addEventListener(MouseEvent.ROLL_OVER,interOver);
				interDisplay.addEventListener(MouseEvent.ROLL_OUT,interOut);
				timer.addEventListener(TimerEvent.TIMER,showTip);
			}
		}
		/**
		 * 对一个可交互的显示对象的提示删除，并清除EventListener和引用
		 */ 
		public static function clearTip(interDisplay:InteractiveObject):void{
			interDisplay.removeEventListener(MouseEvent.ROLL_OVER,interOver);
			interDisplay.removeEventListener(MouseEvent.ROLL_OUT,interOut);
			for(var i:Object in tips){
				if(tips[i][0] == interDisplay){
					tips.splice(uint(i),1);
					break;
				}
			}
		}
		public static function registerLinkTip(display:DisplayObject,linkName:String,initDataFunction:Function,...args):void
		{
			var interDisplay:InteractiveObject = display as InteractiveObject;
			if(interDisplay == null) return;
			var arr:Array = [];
			arr[0] = display;
			arr[1] = linkName;
			arr[2] = initDataFunction;
			arr[3] = args;
			
			linkTips.push(arr);
			interDisplay.addEventListener(MouseEvent.ROLL_OVER,showLinkTip);
			interDisplay.addEventListener(MouseEvent.ROLL_OUT,hideLinkTip);
		}
		/**
		 * 对一个可交互的显示对象的提示删除，并清除EventListener和引用
		 */ 
		public static function clearLinkTip(interDisplay:InteractiveObject,initDataFunction:Function=null):void{
			interDisplay.removeEventListener(MouseEvent.ROLL_OVER,showLinkTip);
			interDisplay.removeEventListener(MouseEvent.ROLL_OUT,hideLinkTip);
			for(var i:Object in linkTips){
				if(linkTips[i][0] == interDisplay){
					linkTips.splice(uint(i),1);
					break;
				}
			}
		}
		public static function getNowShowTip(display:DisplayObject):Sprite
		{
			if(nowDis == display) return nowLinkTip;
			return null;
		}

		private static function showLinkTip(event:MouseEvent):void
		{
			var arr:Array = getDataFromLinkTip(event.currentTarget as DisplayObject);
			if(arr == null) return;
			var sp:Sprite = ObjectFactory.getNewSprite(String(arr[1]));
			nowLinkTip = sp;
			nowDis = event.currentTarget as DisplayObject;
			var fun:Function = arr[2] as Function;
			var oldArgs:Array = arr[3] as Array;
			var callArgs:Array = oldArgs.slice(0);
			if( fun != null)
			{
				callArgs.unshift(arr[0]);
				callArgs.unshift(sp);
				fun.apply(null,callArgs);
			}
			ApplicationDisplay.stage.addChild(sp);
			ApplicationDisplay.stage.addEventListener(MouseEvent.MOUSE_MOVE,followLinkTip);
			followLinkTip();
		}
		private static function hideLinkTip(event:MouseEvent):void
		{
			if(nowLinkTip != null && nowLinkTip.parent != null)
			{
				nowLinkTip.parent.removeChild(nowLinkTip);
				nowLinkTip = null;
			}
			nowDis = null;
			ApplicationDisplay.stage.removeEventListener(MouseEvent.MOUSE_MOVE,followLinkTip);
		}
		private static function followLinkTip(event:MouseEvent=null):void
		{
//			var sta:Stage = StageManager.instance.stage;
//			nowLinkTip.x = int(sta.mouseX);
//			nowLinkTip.y = int(sta.mouseY+21);
//			if(nowLinkTip.x + nowLinkTip.width > sta.stageWidth)
//			{
//				nowLinkTip.x = int(sta.stageWidth - nowLinkTip.width);
//			}
//			if(nowLinkTip.y + nowLinkTip.height > sta.stageHeight)
//			{
//				nowLinkTip.y = int(sta.stageHeight-nowLinkTip.height);
//			}
			if(event != null)
			{
				event.updateAfterEvent();
			}
			nowLinkTip.x = int(ApplicationDisplay.stage.mouseX);
			nowLinkTip.y = int(ApplicationDisplay.stage.mouseY+21);
		}
		private static function getDataFromLinkTip(display:DisplayObject):Array
		{
			for(var i:int=0;i<linkTips.length;i++)
			{
				if(linkTips[i][0] == display)
				{
					return linkTips[i];
				}
			}
			return null;
		}
		
		/**
		 * 设置提示的延迟，单位：毫秒（提示将在此时间后才开始显示，如果在此时间内移开，则不显示提示，对于一组附近的按钮，如果第一个提示已经显示，则后面的提示直接显示，移开这组按钮将重新计时）
		 */ 
		public static function set showDelay(value:uint):void{
			timer.delay = value;
		}
		public static function get showDelay():uint{
			return uint(timer.delay);
		}
		/**
		 * 设置ToolTip的全局样式，影响所有ToolTip实例，样式说明参见Styles
		 */ 
		public static function setDefaultToolTipStyle(ellipse:Number,
													  backgroundTopColor:uint,
													  backgroundBottomColor:uint,
													  backgroundTopAlpha:Number,
													  backgroundBottomAlpha:Number,
													  borderColor:uint,
													  borderAlpha:Number):void{
			defaultToolTipStyle = new Object();
			defaultToolTipStyle.ellipse = ellipse;
			defaultToolTipStyle.backgroundTopColor = backgroundTopColor;
			defaultToolTipStyle.backgroundBottomColor = backgroundBottomColor;
			defaultToolTipStyle.backgroundTopAlpha = backgroundTopAlpha;
			defaultToolTipStyle.backgroundBottomAlpha = backgroundBottomAlpha;
			defaultToolTipStyle.borderColor = borderColor;
			defaultToolTipStyle.borderAlpha = borderAlpha;
		}
		public static function get toolTipInstance():Xtip{
			return ins;
		}
		/**
		 * 立即在舞台上显示一个ToolTip实例
		 */ 
		public static function showAToolTipOnStage(stage:Stage,tip:Object):Xtip{
			Xtip.stage = stage;
			Xtip.tip = tip;
			showTip();
			return ins;
		}
		private static function showTip(event:TimerEvent=null):void{
			timer.stop();
			
			if( ins != null )
			{
				interOut();
				if( ins.parent != null )
				{
					ins.parent.removeChild(ins);
				}
			}
			
			ins = new Xtip();
			stage.addChild(ins);
			ins.x = stage.mouseX;
			ins.y = stage.mouseY+20;
			ins.tip = tip;
			isOn = true;
			if(isFollowMouse == true){
				stage.addEventListener(MouseEvent.MOUSE_MOVE,updateToolTipXY);
			}
			ins.alphaInInit();
		}
		private static function updateToolTipXY(event:MouseEvent):void{
			
			ins.x = stage.mouseX;
			ins.y = stage.mouseY+20;
			if(ins.x+ins.compoWidth+3>stage.stageWidth){
				ins.x = stage.stageWidth - ins.compoWidth-3;
			}
			if(ins.y + ins.compoHeight+3>stage.stageHeight){
				ins.y = stage.mouseY-ins.compoHeight-5;
			}
			event.updateAfterEvent();
		}
		private static function reInitXY(tar:Xtip):void{
			tar.x = stage.mouseX;
			tar.y = stage.mouseY+20;
			tar.visible = true;
			tar.alphaInInit();
			if(tar.x+tar.compoWidth+3>stage.stageWidth){
				tar.x = stage.stageWidth - tar.compoWidth-3;
			}
			if(tar.y + tar.compoHeight+3>stage.stageHeight){
				tar.y = stage.mouseY-tar.compoHeight-5;
			}
		}
		private static function interOver(event:MouseEvent):void{
			var tar:InteractiveObject = event.currentTarget as InteractiveObject;
			var index:uint = 0;
			for(var i:Object in tips){
				if(tips[i][0] == tar){
					index = uint(i) ;
					break;
				}
			}
			target = tips[index][0] as InteractiveObject;
			stage = target.stage;
			tip = tips[index][1];
			if(isOn == true){
				showTip();
				ins.visible = false;
				setTimeout(reInitXY,300,ins);
			}else{
				timer.start();
			}
			clearTimeout(timeOutID);
		}
		private static function interOut(event:MouseEvent = null):void{
			timer.reset();
			if(ins != null ){
				ins.alphaOutInit();
				stage.removeEventListener(MouseEvent.MOUSE_MOVE,updateToolTipXY);
			}
			timeOutID = setTimeout(offIsOnLater,500);
		}
		private static function offIsOnLater():void{
			isOn = false;
		}
	}
}